/*
============================================================================
 Name        : dd_mp3_helper.c
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : dd_mp3_helper.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_mp3_helper.h"
#include "dd_mp3_frame.h"
#include "dd_id3v1_tag.h"
#include "dd_id3v2_tag.h"
#include "dd_audio_file.h"
#include "dd_util.h"
#include "dd_utf8.h"
#include "dd_log.h"

#include "sd_platform.h"


dd_mp3_helper* dd_mp3h_create() 
{
    dd_mp3_helper* helper = (dd_mp3_helper*)dd_malloc(sizeof(dd_mp3_helper)) ;

    __DD_CHECK_MEM(helper, sizeof(dd_mp3_helper), return NULL) ;

    return helper ;
}

void dd_mp3h_destroy(dd_mp3_helper* helper) 
{
    __DD_ASSERT_DEFENSE(helper, return) ;

    if (helper->firstFrame) dd_frame_destroy(helper->firstFrame) ;
    if (helper->id3v1)      dd_id3v1_destroy(helper->id3v1) ;
    if (helper->id3v2)      dd_id3v2_destroy(helper->id3v2) ;
    dd_free(helper) ;
}

int dd_mp3h_read(dd_mp3_helper* helper, sd_file* file, sd_semp* lock) 
{
    int ret = 0 ;

    __DD_ASSERT_DEFENSE(helper, return -1) ;

    if (!helper->id3v2) {
        helper->id3v2 = dd_id3v2_create() ;;
        __DD_ASSERT_DEFENSE(helper->id3v2, return -1) ;
    }
    
    if (!helper->id3v2->done)
        ret = dd_id3v2_read(helper->id3v2, file, 0, lock) ;
    
    if (ret < 0) {
        if (ret == EIdv2TagInComplete) 
            return EDDAgain ;

        if (ret != EIdv2TagNotFound || ret != EIdv2TagNotSupportVersion) 
            return -1 ;
    }
    
    if (!helper->firstFrame)
        helper->firstFrame = dd_frame_create(file, (helper->id3v2 && helper->id3v2->done) ? helper->id3v2->endPos : 0, lock) ;
    
    if (!helper->firstFrame) 
        return EDDAgain ;
    
    if (!helper->id3v1) {
        int fileSize = dd_file_size(file, lock) ;
        if (fileSize > 128)
            helper->id3v1 = dd_id3v1_create(file, fileSize - 128, lock) ;
    }

    return 0 ;
}

DD_UTF8* dd_mp3h_title(dd_mp3_helper* helper) 
{
    DD_UTF8* ret = NULL ;

    __DD_ASSERT_DEFENSE(helper, return NULL) ;

    if (helper->id3v2 && helper->id3v2->done) {
        ret = dd_id3v2_read_string(helper->id3v2, "TIT2") ;
        if (ret)  return ret ;
    }

    if (helper->id3v1) {
        ret = (DD_UTF8*)dd_malloc(30 + 1) ;
        __DD_CHECK_MEM(ret, 30 + 1, return NULL) ;
        memcpy(ret, helper->id3v1->title, 30) ;
        return ret ;
    }

    return NULL ;
}

DD_UTF8* dd_mp3h_album(dd_mp3_helper* helper) 
{
    DD_UTF8* ret = NULL ;

    __DD_ASSERT_DEFENSE(helper, return NULL) ;

    if (helper->id3v2 && helper->id3v2->done) {
        ret = dd_id3v2_read_string(helper->id3v2, "TALB") ;
        if (ret)  return ret ;
    }

    if (helper->id3v1) {
        ret = (DD_UTF8*)dd_malloc(30 + 1) ;
        __DD_CHECK_MEM(ret, 30 + 1, return NULL) ;
        memcpy(ret, helper->id3v1->album, 30) ;
        return ret ;
    }

    return NULL ;
}

DD_UTF8* dd_mp3h_artist(dd_mp3_helper* helper) 
{
    DD_UTF8* ret = NULL ;

    __DD_ASSERT_DEFENSE(helper, return NULL) ;

    if (helper->id3v2 && helper->id3v2->done) {
        ret = dd_id3v2_read_string(helper->id3v2, "TPE1") ;
        if (ret)  return ret ;
    }

    if (helper->id3v1) {
        ret = (DD_UTF8*)dd_malloc(30 + 1) ;
        __DD_CHECK_MEM(ret, 30 + 1, return NULL) ;
        memcpy(ret, helper->id3v1->artist, 30) ;
        return ret ;
    }

    return NULL ;
}

struct __dd_audio_img* dd_mp3h_image(dd_mp3_helper* helper) 
{
    struct __dd_audio_img* ret = NULL ;
    const DD_BYTE*         data = NULL ;
    const DD_BYTE*         loop = NULL ;
    const DD_BYTE*         end = NULL ;
    DD_UINT                len = 0 ;
    int                    encode = 0 ;
    int                    picType = 0;
    DD_UTF8*               mime = NULL;

    __DD_ASSERT_DEFENSE(helper, return NULL) ;

    if (!helper->id3v2 || !helper->id3v2->done) 
        return NULL ;
    
    if (dd_id3v2_read_val(helper->id3v2, "APIC", &data, &len) < 0)
        return NULL ;
    
    loop = data  ;
    end = data + len ;

    encode = loop[0] ;
    loop++ ;

    dd_log_trace("got image description string encode: %d", encode) ;

    /* find image type */
    while(loop < end) {
        if (!loop == 0) 
            break ;
        loop++ ;
    }

    __DD_ASSERT_DEFENSE(loop < (end - 2), return NULL) ;
    __DD_ASSERT_DEFENSE((loop - (data + 1)) > 0, return NULL) ;

    mime = (DD_UTF8*)dd_malloc((loop - (data + 1)) + 1) ;
    __DD_CHECK_MEM(mime, (loop - (data + 1)) + 1, return NULL) ;
    memcpy(mime, data + 1, loop - (data + 1)) ;
    
    loop++ ;
    picType = *loop ;

    dd_log_trace("got image pic type: %d", picType) ;

    /* skip description */
    if (encode == 1 || encode == 2) { /* UCS2 */
        while(loop < end - 1) {
            if (*loop == 0 && *(loop + 1) == 0)
                break ;
            loop += 2 ;
        }

        __DD_ASSERT_DEFENSE(loop < end - 2, dd_free(mime); return NULL) ;
        loop += 2 ;
    } else {
        while(loop < end) {
            if (*loop == 0)
                break ;
            loop++ ;
        }
        __DD_ASSERT_DEFENSE(loop < end - 1, dd_free(mime); return NULL) ;
        loop += 1 ;
    }

    ret = (struct __dd_audio_img*)dd_malloc(sizeof(struct __dd_audio_img)) ;
    __DD_CHECK_MEM(ret, sizeof(struct __dd_audio_img), return NULL) ;
    
    ret->mime = mime ;
    ret->imgData = (DD_BYTE*)dd_malloc(end - loop) ;
    
    __DD_ASSERT_DEFENSE(ret->imgData, return NULL) ;
    memcpy(ret->imgData, loop, end - loop) ;

    return ret ;
}

int dd_mp3h_bitrate(dd_mp3_helper* helper) 
{
    __DD_ASSERT_DEFENSE(helper && helper->firstFrame, return -1) ;
    
    return dd_frame_get_bitrate(helper->firstFrame) ;
}

int dd_mp3h_samplerate(dd_mp3_helper* helper) 
{
    __DD_ASSERT_DEFENSE(helper && helper->firstFrame, return -1) ;

    return dd_frame_get_sample(helper->firstFrame) ;
}

int dd_mp3h_duration(dd_mp3_helper* helper) 
{
    __DD_ASSERT_DEFENSE(helper && helper->firstFrame, return -1) ;

    return dd_frame_get_duration(helper->firstFrame) ;
}

int dd_mp3h_seek(dd_mp3_helper* helper, int second)
{
    __DD_ASSERT_DEFENSE(helper && helper->firstFrame, return -1) ;

    return dd_frame_seek(helper->firstFrame, second) ;
}

/* End of File */
